import { readonly } from 'vue'
import { createI18n } from 'vue-i18n'
import { useLocalStorage } from '@vueuse/core'
import { LANGUAGE, LOCAL_STORAGE_KEYS } from '@/constant'
import API from '@/http'
import en from './locale/en'

const TW = 'zh-tw'
const CN = 'zh-cn'
const EN = 'en'
const ES = 'es'
const FR = 'fr'
const DE = 'de'
const TH = 'th'
const VI = 'vi'
const JA = 'ja'
const KO = 'ko'
const RU = 'ru'
const PT = 'pt'
const ID = 'id'
const AR = 'ar'
const HI = 'hi'

/**
 * @description 目前可使用的語系
 * 如果需要新增語系，首先要先到 src/i18n/locales 裡面新增語系檔案
 * 然後再到這裡新增語系選項
 * 小心[dash]跟[underline]的差異
 */
const loadLocales = Object.freeze([
  { label: 'en', value: EN },
  { label: 'zh_cn', value: CN },
  { label: 'zh_tw', value: TW },
  { label: 'es', value: ES },
  { label: 'fr', value: FR },
  { label: 'de', value: DE },
  { label: 'th', value: TH },
  { label: 'vi', value: VI },
  { label: 'ja', value: JA },
  { label: 'ko', value: KO },
  { label: 'ru', value: RU },
  { label: 'pt', value: PT },
  { label: 'id', value: ID },
  { label: 'ar', value: AR },
  { label: 'hi', value: HI },
])

const loadedLanguages = [EN]

const i18n = createI18n({
  locale: EN,
  fallbackLocale: EN,
  messages: {
    [EN]: en,
  },
})

const storageLocale = useLocalStorage(LOCAL_STORAGE_KEYS.LOCALE)

let currentLoadLang
let nextLoadLang

function setI18nLanguage(lang) {
  i18n.global.locale.value = lang
  storageLocale.value = lang
  return lang
}

function loadLanguage(lang) {
  if (currentLoadLang) {
    nextLoadLang = lang
    return
  }

  currentLoadLang = lang

  const promise =
    i18n.global.locale.value === lang || loadedLanguages.includes(lang)
      ? Promise.resolve(setI18nLanguage(lang))
      : import(`./locale/${lang}.ts`).then((messages) => {
          i18n.global.setLocaleMessage(lang, messages.default)
          loadedLanguages.push(lang)
          return setI18nLanguage(lang)
        })

  promise.then(async () => {
    currentLoadLang = undefined
    if (nextLoadLang) {
      const lang = nextLoadLang
      nextLoadLang = undefined
      await loadLanguage(lang)
    }
  })

  return promise
}

function getLang(langCode) {
  const lang = langCode.replace('_', '-').toLowerCase()
  const localeCodes = loadLocales.map((locale) => locale.value)
  let matches = null
  localeCodes.forEach((code) => {
    if (lang.includes(code)) matches = code
    if (lang.includes('zh-hk')) matches = TW
  })
  return matches || EN
}

export default i18n

export const locale = readonly(i18n.global.locale)
export const locales = loadLocales
export const $t = i18n.global.t

export async function initI18n() {
  const defaultLang = storageLocale.value || getLang(navigator.language?.toLocaleLowerCase())
  try {
    await setLocale(defaultLang)
    console.log('i18n initialize successfully.')
    return i18n
  } catch (e) {
    console.error(e)
  }
}

export async function setLocale(langCode) {
  const lang = getLang(langCode)

  // 必須在 loadLanguage 完成後才跟後端同步語言(syncBackendLocale)
  // 但是 loadLanguage 完成後 storageLocale 會被替換掉
  // 所以必須要 loadLanguage 之前先將是否要同步後端語言確定好
  const needSyncBackendLocale = storageLocale.value !== lang

  await loadLanguage(lang)

  if (needSyncBackendLocale) {
    await syncBackendLocale()
  }

  return lang
}

export async function syncBackendLocale() {
  await API.Auth.language({ data: { language: LANGUAGE[storageLocale.value] } })
}

export function contains(lang) {
  const localeValues = loadLocales.map((locale) => locale.value)
  return localeValues.indexOf(lang) !== -1
}
